//
//  BEViewStyleExtension.swift
//  BasicExtensions
//
//  Created by 范晓鑫 on 2023/6/16.
//

import UIKit

// MARK: Button State Plugin

/// Button状态插件
public protocol BEButtonStatePluginType {
    /// 绑定到按钮
    func attach(for button: UIButton)
    /// 从按钮解除绑定
    func detach(for button: UIButton)
    /// 激活该状态
    func active(for button: UIButton)
    /// 反激活该状态
    func deactive(for button: UIButton)
    /// Button大小变化且当前是激活状态时触发
    func resize(for button: UIButton)
}
extension BEButtonStatePluginType {
    public func attach(for button: UIButton) { }
    public func detach(for button: UIButton) { }
    public func resize(for button: UIButton) { }
}
/// 插件ID
public typealias BEButtonStatePluginIdentifier = BENilableStringIdentifier
/// 负责管理Button状态插件
public class BEButtonStatePluginManager {
    class PluginInfo {
        /// 当前是否激活中
        var isActived: Bool = false
        var plugin: BEButtonStatePluginType
        init( plugin: BEButtonStatePluginType) {
            self.plugin = plugin
        }
    }
    weak var button: UIButton? {
        willSet {
            if let button {
                self.plugins.values.forEach { list in
                    list.values.forEach { info in
                        self.detachPlugin(info, for: button)
                    }
                }
                self.stateObs.removeAll()
            }
            if let newValue {
                self.plugins.values.forEach { list in
                    list.values.forEach { info in
                        info.plugin.attach(for: newValue)
                    }
                }
                self.currentState = newValue.state
                self.addObservers(for: newValue)
                self.updatePluginState(for: newValue)
            }
        }
    }
    /// 所有插件列表 [状态:  插件列表]
    var plugins: [UInt: [BEButtonStatePluginIdentifier: PluginInfo]] = [:]
    /// 状态监听
    var stateObs: [NSKeyValueObservation] = []
    /// 当前状态
    var currentState: UIButton.State
    /// 可处理的状态
    private let processStates: [UIButton.State] = [.highlighted, .selected, .disabled]
    init(button: UIButton) {
        self.button = button
        self.currentState = button.state
        self.addObservers(for: button)
    }
    /// 添加状态监听
    private func addObservers(for button: UIButton) {
        let obEnabled = button.observe(\.isEnabled, options: .new) { [weak self] button, _ in
            self?.checkState(for: button)
        }
        let obHighlighted = button.observe(\.isHighlighted, options: .new) { [weak self] button, _ in
            self?.checkState(for: button)
        }
        let obSelected = button.observe(\.isSelected, options: .new) { [weak self] button, _ in
            self?.checkState(for: button)
        }
        let obSize = button.observe(\.bounds, options: .new) { [weak self] button, size in
            if size.newValue != nil {
                self?.plugins.values.forEach({ list in
                    list.values.forEach { info in
                        if info.isActived {
                            info.plugin.resize(for: button)
                        }
                    }
                })
            }
        }
        self.stateObs = [obEnabled, obHighlighted, obSelected, obSize]
    }
    /// 状态是可以复合的，拆成单个值
    private func keys(for state: UIButton.State) -> [UInt] {
        if state == .normal {
            return [state.rawValue]
        }
        return processStates.filter(state.contains(_:)).map { $0.rawValue }
    }
    /// 根据状态获取当前需要触发的所有状态
    private func handleKeys(for state: UIButton.State) -> [UInt] {
        if state == .normal {
            return [state.rawValue]
        }
        // 若被禁用，则其他状态都无视
        if state.contains(.disabled) {
            return [UIButton.State.disabled.rawValue]
        }
        // 其他状态默认同时生效
        return processStates.filter(state.contains(_:)).map { $0.rawValue }
    }
    /// 添加插件
    public func setPlugin(_ plugin: BEButtonStatePluginType?, identifier: BEButtonStatePluginIdentifier = .default, for state: UIButton.State) {
        if let plugin {
            self.keys(for: state).forEach { key in
                if var list = self.plugins[key] {
                    if let button {
                        list[identifier]?.plugin.detach(for: button)
                        plugin.attach(for: button)
                    }
                    list[identifier] = .init(plugin: plugin)
                    self.plugins[key] = list
                } else {
                    self.button ??> plugin.attach(for:)
                    self.plugins[key] = [identifier: .init(plugin: plugin)]
                }
            }
            if let button {
                self.updatePluginState(for: button)
            }
        } else {
            self.removePlugin(identifier, for: state)
        }
    }
    /// 移除插件
    public func removePlugin(_ identifier: BEButtonStatePluginIdentifier = .default, for state: UIButton.State) {
        self.keys(for: state).forEach { key in
            if var list = self.plugins[key], let plugin = list[identifier] {
                if let button {
                    self.detachPlugin(plugin, for: button)
                }
                list.removeValue(forKey: identifier)
                self.plugins[key] = list
            }
        }
        if let button {
            self.updatePluginState(for: button)
        }
    }
    /// 移除指定状态下全部插件
    public func removeAllPlugins(for state: UIButton.State) {
        self.keys(for: state).forEach { key in
            if let list = self.plugins[key] {
                if let button {
                    list.values.forEach { plugin in
                        self.detachPlugin(plugin, for: button)
                    }
                }
                self.plugins.removeValue(forKey: key)
            }
        }
        if let button {
            self.updatePluginState(for: button)
        }
    }
    /// 移除全部插件
    public func removeAllPlugins() {
        if let button {
            self.plugins.values.forEach { list in
                list.values.forEach { plugin in
                    self.detachPlugin(plugin, for: button)
                }
            }
        }
        self.plugins.removeAll()
    }
    private func detachPlugin(_ info: PluginInfo, for button: UIButton) {
        info.plugin.detach(for: button)
        self.deactivePlugin(info, for: button)
    }
    private func deactivePlugin(_ info: PluginInfo, for button: UIButton) {
        if info.isActived {
            info.isActived = false
            info.plugin.deactive(for: button)
        }
    }
    private func activePlugin(_ info: PluginInfo, for button: UIButton) {
        if !info.isActived {
            info.isActived = true
            info.plugin.active(for: button)
        }
    }
    private func checkState(for button: UIButton) {
        if button.state != self.currentState {
            self.currentState = button.state
            self.updatePluginState(for: button)
        }
    }
    /// 更新所有插件状态
    private func updatePluginState(for button: UIButton) {
        var normalPlugins = self.plugins[UIButton.State.normal.rawValue] ?? [:]
        let keys = self.handleKeys(for: self.currentState)
        self.plugins.filter { $0.key != UIButton.State.normal.rawValue }
            .forEach { (key, plugins) in
                // 不在该状态下的直接禁用
                if !keys.contains(key) {
                    plugins.values.forEach { plugin in
                        self.deactivePlugin(plugin, for: button)
                    }
                } else {
                    plugins.forEach { (identifier, plugin) in
                        // 如果当前状态和普通状态都有则使用当前的
                        if let normalPlugin = normalPlugins[identifier] {
                            self.deactivePlugin(normalPlugin, for: button)
                            normalPlugins.removeValue(forKey: identifier)
                        }
                        self.activePlugin(plugin, for: button)
                    }
                }
            }
        // 剩下的普通状态说明是当前状态没有的，则全部激活
        normalPlugins.values.forEach { plugin in
            self.activePlugin(plugin, for: button)
        }
    }
}

extension UIButton {
    /// 插件管理器
    var statePluginManager: BEButtonStatePluginManager {
        return self.extend.object(for: "basicExtensions.buttonStatePluginManager", createIfNil: BEButtonStatePluginManager(button: self))
    }
    /// 添加插件
    public func setPlugin(_ plugin: BEButtonStatePluginType?, identifier: BEButtonStatePluginIdentifier = .default, for state: State) {
        self.statePluginManager.setPlugin(plugin, identifier: identifier, for: state)
    }
    /// 移除插件
    public func removePlugin(_ identifier: BEButtonStatePluginIdentifier = .default, for state: UIButton.State) {
        self.statePluginManager.removePlugin(identifier, for: state)
    }
    /// 移除指定状态下全部插件
    public func removeAllPlugins(for state: UIButton.State) {
        self.statePluginManager.removeAllPlugins(for: state)
    }
    /// 移除全部插件
    public func removeAllPlugins() {
        self.statePluginManager.removeAllPlugins()
    }
}

// MARK: ViewStyle

public protocol BEViewStyleType: BEButtonStatePluginType {
    /// 绑定到View
    func add(to view: UIView)
    /// 从View解除绑定
    func remove(from view: UIView)
    /// 大小变化时触发
    func layout(for view: UIView)
}
extension BEViewStyleType {
    /// 激活该状态
    public func active(for button: UIButton) {
        self.add(to: button)
    }
    /// 反激活该状态
    public func deactive(for button: UIButton) {
        self.remove(from: button)
    }
    public func resize(for button: UIButton) {
        self.layout(for: button)
    }
    public func layout(for view: UIView) { }
}
/// 插件ID
public typealias BEViewStyleIdentifier = BENilableStringIdentifier

/// 负责管理View插件
public class BEViewStyleManager {
    class StyleInfo {
        /// 当前是否激活中
        var isActived: Bool = false
        var style: BEViewStyleType
        init( style: BEViewStyleType) {
            self.style = style
        }
    }
    weak var view: UIView? {
        willSet {
            if let view {
                self.styles.values.forEach { info in
                    self.removeStyle(info, for: view)
                }
                self.obs.removeAll()
            }
            if let newValue {
                self.styles.values.forEach { info in
                    self.addStyle(info, for: newValue)
                }
                self.addObservers(for: newValue)
            }
        }
    }
    /// 所有样式列表
    var styles: [BEViewStyleIdentifier: StyleInfo] = [:]
    /// 状态监听
    var obs: [NSKeyValueObservation] = []
    init(view: UIView) {
        self.view = view
        self.addObservers(for: view)
    }
    /// 添加状态监听
    private func addObservers(for view: UIView) {
        let obAction: (UIView, NSKeyValueObservedChange<CGRect>) -> Void = { [weak self] view, size in
            if size.newValue != nil {
                self?.styles.values.forEach { style in
                    if style.isActived {
                        style.style.layout(for: view)
                    }
                }
            }
        }
        let obSize = view.observe(\.bounds, options: .new, changeHandler: obAction)
        let obFrame = view.observe(\.frame, options: .new, changeHandler: obAction)
        self.obs = [obSize, obFrame]
    }
    /// 添加样式
    public func setStyle(_ style: BEViewStyleType?, identifier: BEViewStyleIdentifier = .default) {
        if let style {
            self.removeStyle(identifier)
            let info = StyleInfo(style: style)
            self.styles[identifier] = info
            if let view {
                self.addStyle(info, for: view)
            }
        } else {
            self.removeStyle(identifier)
        }
    }
    /// 移除样式
    public func removeStyle(_ identifier: BEViewStyleIdentifier = .default) {
        if let style = self.styles[identifier] {
            if let view {
                self.removeStyle(style, for: view)
            }
            self.styles.removeValue(forKey: identifier)
        }
    }
    /// 移除全部样式
    public func removeAllStyles() {
        if let view {
            self.styles.values.forEach { style in
                self.removeStyle(style, for: view)
            }
        }
        self.styles.removeAll()
    }
    private func addStyle(_ info: StyleInfo, for view: UIView) {
        if !info.isActived {
            info.isActived = true
            info.style.add(to: view)
        }
    }
    private func removeStyle(_ info: StyleInfo, for view: UIView) {
        if info.isActived {
            info.isActived = false
            info.style.remove(from: view)
        }
    }
}

extension UIView {
    /// 样式管理器
    var styleManager: BEViewStyleManager {
        return self.extend.object(for: "basicExtensions.viewStyleManager", createIfNil: BEViewStyleManager(view: self))
    }
    /// 添加样式
    public func setStyle(_ style: BEViewStyleType?, identifier: BEViewStyleIdentifier = .default) {
        self.styleManager.setStyle(style, identifier: identifier)
    }
    /// 移除样式
    public func removeStyle(_ identifier: BEViewStyleIdentifier = .default) {
        self.styleManager.removeStyle(identifier)
    }
    /// 移除全部样式
    public func removeAllStyles() {
        self.styleManager.removeAllStyles()
        if let button = self as? UIButton {
            button.removeAllPlugins()
        }
    }
}
extension UIButton {
    /// 添加样式
    public func setStyle(_ style: BEViewStyleType?, identifier: BEViewStyleIdentifier = .default, for state: State) {
        self.setPlugin(style, identifier: identifier, for: state)
    }
    /// 移除样式
    public func removeStyle(_ identifier: BEViewStyleIdentifier = .default, for state: UIButton.State) {
        self.removePlugin(identifier, for: state)
    }
    /// 移除指定状态下全部样式
    public func removeAllStyles(for state: UIButton.State) {
        self.removeAllPlugins(for: state)
    }
}

// MARK: 组合样式

public struct BEButtonStatePluginGroup :BEButtonStatePluginType {
    public let plugins: [BEButtonStatePluginType]
    /// 绑定到按钮
    public func attach(for button: UIButton) {
        self.plugins.forEach { $0.attach(for: button) }
    }
    /// 从按钮解除绑定
    public func detach(for button: UIButton) {
        self.plugins.forEach { $0.detach(for: button) }
    }
    /// 激活该状态
    public func active(for button: UIButton) {
        self.plugins.forEach { $0.active(for: button) }
    }
    /// 反激活该状态
    public func deactive(for button: UIButton) {
        self.plugins.forEach { $0.deactive(for: button) }
    }
    /// Button大小变化且当前是激活状态时触发
    public func resize(for button: UIButton) {
        self.plugins.forEach { $0.resize(for: button) }
    }
}
extension UIButton {
    /// 添加插件
    public func setPlugins(_ plugins: BEButtonStatePluginType..., identifier: BEButtonStatePluginIdentifier = .default, for state: UIButton.State) {
        self.setPlugin(BEButtonStatePluginGroup(plugins: plugins), identifier: identifier, for: state)
    }
}

public struct BEViewStyleGroup : BEViewStyleType {
    public let styles: [BEViewStyleType]
    /// 绑定到按钮
    public func attach(for button: UIButton) {
        self.styles.forEach { $0.attach(for: button) }
    }
    /// 从按钮解除绑定
    public func detach(for button: UIButton) {
        self.styles.forEach { $0.detach(for: button) }
    }
    /// 激活该状态
    public func active(for button: UIButton) {
        self.styles.forEach { $0.active(for: button) }
    }
    /// 反激活该状态
    public func deactive(for button: UIButton) {
        self.styles.forEach { $0.deactive(for: button) }
    }
    /// Button大小变化且当前是激活状态时触发
    public func resize(for button: UIButton) {
        self.styles.forEach { $0.resize(for: button) }
    }
    /// 绑定到View
    public func add(to view: UIView) {
        self.styles.forEach { $0.add(to: view) }
    }
    /// 从View解除绑定
    public func remove(from view: UIView) {
        self.styles.forEach { $0.remove(from: view) }
    }
    /// 大小变化时触发
    public func layout(for view: UIView) {
        self.styles.forEach { $0.layout(for: view) }
    }
}

extension UIButton {
    /// 添加样式
    public func setStyles(_ styles: BEViewStyleType..., identifier: BEViewStyleIdentifier = .default, for state: State) {
        self.setStyle(BEViewStyleGroup(styles: styles), identifier: identifier, for: state)
    }
}
extension UIView {
    /// 添加样式
    public func setStyles(_ styles: BEViewStyleType..., identifier: BEViewStyleIdentifier = .default) {
        self.setStyle(BEViewStyleGroup(styles: styles), identifier: identifier)
    }
}
